﻿using System;
using System.Net;
using System.Web;
using Sherwood.Security;
using log4net;

namespace Sherwood.SignOn.Client
{
    public class SignOnServicesClient
    {
        private static readonly ILog Log = LogManager.GetLogger(typeof(SignOnServicesClient));

        public string BaseUrl { get; private set; }

        public string ClientCode { get; private set; }

        public string RsaPrivateKey { get; private set; }

        /// <summary>
        /// Instansiates a new instance of SignOnServicesClient which can be used to make requests to the 
        /// single sign on server.
        /// </summary>
        /// <param name="baseUrl">Base  URL of single sign on service (e.g. http://signon.sherwood.local)</param>
        /// <param name="clientCode">Trusted client code (unique and known by server).</param>
        /// <param name="rsaPrivateKey">Trusted client private key (server should know public key).</param>
        public SignOnServicesClient(string baseUrl, string clientCode, string rsaPrivateKey)
        {
            BaseUrl = baseUrl;
            ClientCode = clientCode;
            RsaPrivateKey = rsaPrivateKey;
        }

        /// <summary>
        /// Returns the profile of the user associated with the signOnSessionId.
        /// </summary>
        /// <param name="signOnSessionId"></param>
        /// <returns>getUserProfileResponse object if profile could be retrieved, otherwise null.</returns>
        public getUserProfileResponse GetUserProfile(Guid signOnSessionId)
        {
            getUserProfileResponse profile = null;
            if (signOnSessionId != Guid.Empty)
            {
                //Assemble request for user profile to Sso service
                string clientCode = HttpUtility.UrlEncode(ClientCode);
                string timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
                string signatureData = clientCode + "|" + timestamp + "|" + signOnSessionId;
                string signature = null;

                Rsa rsa = Rsa.FromPrivateKey(RsaPrivateKey);
                signature = rsa.SHA1Sign(signatureData);


                //Perform request to Sso GetUserProfile service
                string requestUrl = BaseUrl.Trim().TrimEnd('/') + "/Services/GetSessionProfile?ClientCode=" + HttpUtility.UrlEncode(clientCode) + "&Timestamp=" + HttpUtility.UrlEncode(timestamp) + "&SignOnSessionId=" + HttpUtility.UrlEncode(signOnSessionId.ToString()) + "&Signature=" + HttpUtility.UrlEncode(signature);

                WebRequest request = HttpWebRequest.Create(requestUrl);
                WebResponse response = request.GetResponse();
                if (response != null)
                {
                    System.IO.Stream responseStream = response.GetResponseStream();
                    if (responseStream != null)
                    {
                        //Retrieve profile information from server response
                        System.IO.StreamReader reader = new System.IO.StreamReader(responseStream);
                        string xml = reader.ReadToEnd();
                        try
                        {
                            profile = getUserProfileResponse.Parse(xml);
                        }
                        catch (Exception)
                        {
                            string exceptionDescription = "";
                            try
                            {
                                serviceException exceptionXml = serviceException.Parse(xml);
                                exceptionDescription = "Exception: " + exceptionXml.message + "\n\nInner exception: " +
                                                       exceptionXml.innerException;
                            }
                            catch (Exception)
                            {
                                exceptionDescription = xml;
                            }
                            Log.Error("The following exception occured on the sign-on server: \n\n" + exceptionDescription);
                            profile = null;
                            throw new Exception("The following exception occured on the sign-on server: \n\n" + exceptionDescription);
                        }
                    }
                }
            }
            return profile;
        }
    }
}


